package ch.fortysix.maven.plugin.postaman.surfire


/**
 * 
 */

import java.io.File;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.List;

import org.apache.maven.doxia.siterenderer.Renderer;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.reporting.MavenReportException;

import ch.fortysix.maven.plugin.postaman.AbstractSenderMojo;
import ch.fortysix.maven.report.support.HtmlExtractor;
import ch.fortysix.maven.report.support.SinkReporter;


/**
 * Sends mails based on surefire (test) results.
 * 
 * @author Domi
 * @goal surefire-mail
 * @phase site
 */
class SurefireMailMojo extends AbstractSenderMojo {
	
	
	/**
	 * The file pattern to be used to search for the surefire reports in the 'testReportsDirectory'-directory.
	 * 
	 * @parameter default-value="TEST-.*.xml"
	 */	
	String reportFilePattern
	
	/**
	 * This allows to redefine the condition to send the mail. e.g. one can define that there 
	 * must not be more then 20 skipped test cases (<code>skipped > 20</code>).
	 * The default condition sends mails if there are any errors.
	 * The following variables are available for usage in the condition:
	 * <ul>
	 * 	<li><code>errors</code>: number of all errors while running surefire</li>
	 * 	<li><code>skipped</code>: number of all skipped test cases</li>
	 * 	<li><code>failures</code>: number of all failures in the test cases</li>
	 * 	<li><code>total</code>: number of all test cases</li>
	 * </ul>
	 * Other (usefull or not...) examples:
	 * <ul>
	 * 	<li><code>errors > 0</code> : sends a mail only if there are errors</li>
	 * 	<li><code>skipped > failures</code> : sends mails if there are more skipped then failed test cases</li>
	 * 	<li><code>total == skipped</code> : Sends mails if all tests are skipped</li>
	 * </ul>
	 * To avoid problems with XML syntax, one can use a <a href="http://www.w3schools.com/xmL/xml_cdata.asp">CDATA element</a>.
	 * The default only send a mail if there are errors or failures, but ignores the skipped ones.
	 * @parameter default-value="errors > 0 || failures > 0"
	 */
	String groovyCondition
	
	/**
	 * Base directory where all surefire test reports are read from.  
	 * @parameter expression="${project.build.directory}/surefire-reports" default-value="${project.build.directory}/surefire-reports"
	 */	
	File testReportsDirectory	
	
	/**
	 * The generated surefire html report (previously generated by 'maven-surefire-report-plugin'). 
	 * @parameter default-value="${project.build.directory}/site/surefire-report.html"
	 */
	File surefireReportHtml;
	
	
	protected boolean prepareMojo(){
		if(!testReportsDirectory || !testReportsDirectory.exists()){
			getLog().error """
 'testReportsDirectory' could not be found ($testReportsDirectory).
 - Do you have the 'maven-surefire-plugin' configured or are the reports generated to a different directory?
 - Is the 'maven-surefire-plugin' executed befor this plugin?
"""
			return false
		}
		if(surefireReportHtml && !surefireReportHtml.exists()){
			getLog().warn """
 The postman-surefire mails will not contain HTML, because the surefire report could not be found.
 - 'maven-surefire-report-plugin' must run befor 'maven-postman-plugin', set phase to 'site'!
"""
		}
		return true
	}
	
	public void executeMojo() throws MojoExecutionException, MojoFailureException {
		
		// Analyze the test reports
		TestReportUtil util = new TestReportUtil(log: getLog())
		def suiteReports = util.getTestSuiteReport( testReportsDirectory, reportFilePattern)
		
		////////////////////////////////////////////////////
		//
		// evaluate if the condition tells us to send the mails
		
		// - prepare variables
		def errors = suiteReports.inject(0) { count, suiteReport ->
			count + suiteReport?.errors
		}
		log.debug "test ERRORS: "+ errors
		def skipped = suiteReports.inject(0) { count, suiteReport ->
			count + suiteReport?.skipped
		}
		log.debug "test SKIPPED: "+ skipped
		def failures = suiteReports.inject(0) { count, suiteReport ->
			count + suiteReport?.failures
		}
		log.debug "test FAILURES: "+ failures
		def tests = suiteReports.inject(0) { count, suiteReport ->
			count + suiteReport?.tests
		}
		log.debug "test TOTAL: "+ tests
		
		// - bind the variables
		Binding binding = new Binding();
		binding.setVariable("errors", errors);
		binding.setVariable("skipped", skipped);
		binding.setVariable("failures", failures);
		binding.setVariable("total", tests);
		
		// - evaluate
		log.info "evaluating groovy condition [$groovyCondition]"
		GroovyShell shell = new GroovyShell(binding);
		def value 
		try{
			value = shell.evaluate(groovyCondition);
		}catch (Exception e){
			throw new MojoExecutionException("postman is not able to evaluate the configured 'groovyCondition': $groovyCondition", e)
		}
		boolean sendIt = value as Boolean
		
		// we send the same report to all receivers
		if(sendIt){
			def mail = this.createMail(suiteReports)
			context.run ([mail])
		}else{
			log.info "postman surfire report groovy condition [$groovyCondition] not fulfilled, don't send the mails..."
		}
	}
	
	
	/**
	 * create the mail to be send/reported. 
	 */
	public Map createMail(List suiteReports){
		
		def html = htmlMessageFile?.text
		html = html ? html : htmlMessage
		def txt = textMessageFile?.text
		txt = txt ? txt : textMessage
		
		if(!html){
			// if no html was configured in the plugin, we try to use the html report
			if(surefireReportHtml && surefireReportHtml.exists()){
				// get the html of the generated surefire report (maven-surefire-report-plugin)
				if(surefireReportHtml.text){
					HtmlExtractor htmlExtractor = new HtmlExtractor()
					html = htmlExtractor.extractHTMLTagById(html: surefireReportHtml.text, tagName: "div", tagId: "bodyColumn")
				}
				
			} else{
				log.warn "can't include HTML report to postman-surefire mail ($surefireReportHtml not found)"
			}
		}
		
		if(!txt){
			// if no text was configured in the plugin, we create a basic report our self
			def body = new StringBuilder()
			suiteReports.each{ report -> 
				body << "\n"
				body << report.name << " (total: " << report.tests <<  ") errors: " << report.errors <<  ", failures: " <<  report.failures << ", skipped: " <<  report.skipped
			}
			txt = body.toString()
		}
		
		if(!html){
			html = txt
		}
		
		return [receivers: receivers, from: from, subject: subject, text: txt, html: html]
	}
	
}
